home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
machserver
/
1.098
/
prof
/
profProfil.c
< prev
Wrap
C/C++ Source or Header
|
1990-10-19
|
7KB
|
314 lines
/*
* profProfil.c --
*
* Profil system call.
*
* Copyright 1989 Regents of the University of California
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. The University of California
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*/
#ifndef lint
static char rcsid[] = "$Header: /sprite/src/kernel/prof/RCS/profProfil.c,v 9.3 90/10/19 15:52:28 rab Exp $";
#endif /* not lint */
#include <assert.h>
#include "sprite.h"
#include "proc.h"
#include "prof.h"
#include "sync.h"
#include "vm.h"
/*
* Program counter recorded by the interrupt handler.
*/
/* int Prof_InterruptPC; */
/*
* Monitor lock for this module.
*/
#ifndef lint
static Sync_Lock profilLock = Sync_LockInitStatic("Prof:profilLock");
#else
static Sync_Lock profilLock;
#endif
#define LOCKPTR &profilLock
static void tick _ARGS_((Timer_Ticks time, ClientData clientData));
/*
* Information that is passed to Timer_ScheduleRoutine() to
* queue tick() for invocation by the call back timer
* interrupt handler.
*/
Timer_QueueElement profTimer_QueueElement = {
{ NULL, NULL }, /* links */
tick, /* routine */
0, /* time */
1234, /* clientData */
FALSE, /* processed */
0 /* interval */
};
/*
* Count of the number of processes being profiled.
*/
static int profCount = 0;
/*
*----------------------------------------------------------------------
*
* profProfil --
*
* Profil system call.
*
* Results:
* Always returns success.
*
* Side effects:
* Same as Prof_Enable.
*
*----------------------------------------------------------------------
*/
ReturnStatus
Prof_Profil(buffer, bufSize, offset, scale)
short *buffer;
int bufSize;
int offset;
int scale;
{
Prof_Enable(Proc_GetCurrentProc(), buffer, bufSize, offset, scale);
return SUCCESS;
}
/*
*----------------------------------------------------------------------
*
* Prof_Enable --
*
* Enables or disables the profiling of a process.
*
* Results:
* None.
*
* Side effects:
* Changes the Profiling fields in the Proc_ControlBlock, increments
* or decrements ProfCount, and schedules or deschedules tick()
* in the call back queue.
*
*----------------------------------------------------------------------
*/
void
Prof_Enable(procPtr, buffer, bufSize, offset, scale)
Proc_ControlBlock *procPtr;
short *buffer;
int bufSize;
int offset;
int scale;
{
#if 0
printf("Prof_Enable(p = %x, id = %x, buffer = %08x, bufSize = %d, offset = %d, scale = %d\n",
procPtr, procPtr->processID, buffer, bufSize, offset, scale);
printf("profCount = %d\n", profCount);
#endif
assert(procPtr != (Proc_ControlBlock *) NIL);
LOCK_MONITOR;
if (scale != 0 && scale != 1 && procPtr->Prof_Scale == 0) {
/*
* If the profile routine has not already been scheduled for invocation
* by the call back timer, then schedule it.
*/
if (profCount == 0) {
profTimer_QueueElement.interval = 20 * timer_IntOneMillisecond;
Timer_ScheduleRoutine(&profTimer_QueueElement, TRUE);
}
++profCount;
} else if ((scale == 0 || scale == 1) && procPtr->Prof_Scale != 0) {
assert(profCount > 0);
/*
* Disable profiling. If there are no other processes being profiled,
* then remove tick() from the call back queue.
*/
--profCount;
if (profCount == 0) {
Timer_DescheduleRoutine(&profTimer_QueueElement);
}
}
procPtr->Prof_Buffer = buffer;
procPtr->Prof_BufferSize = bufSize;
procPtr->Prof_Offset = offset;
procPtr->Prof_Scale = scale;
procPtr->Prof_PC = 0;
UNLOCK_MONITOR;
return;
}
/*
*----------------------------------------------------------------------
*
* tick --
*
* If any processes are scheduled for profiling this routine
* is called on each call back timer interrupt.
*
* Results:
* Always returns SUCCESS.
*
* Side effects:
*
* If the current process is scheduled for profiling then the
* specialHandling flag is set, and the current PC is recorded in
* the process control block.
*
*----------------------------------------------------------------------
*/
/*ARGSUSED*/
static void
tick(time, clientData)
Timer_Ticks time;
ClientData clientData;
{
Proc_ControlBlock *curProcPtr;
LOCK_MONITOR;
assert(profCount != 0);
#if 0
if (profCount == 0) {
printf("Descheduling profil timer\n");
Timer_DescheduleRoutine(&profTimer_QueueElement);
return;
}
#endif
#if 0
printf("Prof tick, mach_KernelMode = %d, profCount = %d\n",
mach_KernelMode, profCount);
#endif
assert(clientData == profTimer_QueueElement.clientData);
if (!mach_KernelMode) {
assert(profCount);
curProcPtr = Proc_GetCurrentProc();
assert(curProcPtr != (Proc_ControlBlock *) NIL);
#if 0
printf("Prof tick, scale=%d, pc=%08x, profCount = %d\n",
curProcPtr->Prof_Scale, curProcPtr->Prof_PC, profCount);
#endif
if (curProcPtr->Prof_Scale >= 2) {
curProcPtr->specialHandling = TRUE;
}
}
Timer_ScheduleRoutine(&profTimer_QueueElement, TRUE);
UNLOCK_MONITOR;
return;
}
/*
*----------------------------------------------------------------------
*
* Prof_RecordPC --
*
*
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
Prof_RecordPC(procPtr)
Proc_ControlBlock *procPtr;
{
short *ptr;
union {
short shrt;
char c[2];
} u;
assert(procPtr->Prof_Scale);
ptr = &procPtr->Prof_Buffer[(((procPtr->Prof_PC -
procPtr->Prof_Offset) * procPtr->Prof_Scale) >> 16) / sizeof(*ptr)];
/*
* Make sure the pointer is in the proper range.
*/
if (ptr < procPtr->Prof_Buffer || ptr >=
&procPtr->Prof_Buffer[procPtr->Prof_BufferSize/sizeof(short)]) {
procPtr->Prof_PC = 0;
return;
}
/*
* Copy the counter in, increment it, and copy it back out.
*/
if (Vm_CopyInProc(sizeof(short), procPtr, (Address) ptr, u.c, 1)
!= SUCCESS) {
Prof_Disable(procPtr);
return;
}
++u.shrt;
#if 0
printf("Prof_RecordPC(), shrt = %d, profCount = %d\n", u.shrt, profCount);
#endif
if (Vm_CopyOutProc(sizeof(short), u.c, 1, procPtr, (Address) ptr)
!= SUCCESS) {
Prof_Disable(procPtr);
return;
}
procPtr->Prof_PC = 0;
return;
}
/*
*----------------------------------------------------------------------
*
* Prof_Disable --
*
* Disable profiling of a process.
*
* Results:
* None.
*
* Side effects:
* Clears the Prof_Scale and Prof_PC fields of the PCB, and decrements
* the count of profiled processes. If no other processes are being
* profiled, removes the profil timer from the callback timer queue.
*
*----------------------------------------------------------------------
*/
void
Prof_Disable(procPtr)
Proc_ControlBlock *procPtr;
{
LOCK_MONITOR;
if (procPtr->Prof_Scale != 0) {
assert(profCount > 0);
procPtr->Prof_Scale = 0;
procPtr->Prof_PC = 0;
--profCount;
if (profCount == 0) {
Timer_DescheduleRoutine(&profTimer_QueueElement);
}
}
UNLOCK_MONITOR;
return;
}